#region Directives
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;

using VisualStudioSensor;
using TeamFoundationServerSensor;
#endregion

/// <summary>
/// Web Service Endpoint for the <seealso href="WorkItemChangedEvent"/>
/// </summary>
/// <remarks>
/// To Register this Notification Endpoint you will need to use the <seealso href="http://blogs.msdn.com/psheill/archive/2006/02/01/522386.aspx">BisSubscribe.exe</seealso> tool. 
/// For more information about Team Foundation Server Notifications <seealso href="http://blogs.msdn.com/buckh/archive/2006/04/10/event_filtering.aspx"/>
/// </remarks>
[WebService(Namespace = "http://schemas.conchango.com/TeamFoundation/2005/06/Services/Notification/Extensibility", Description = "")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WorkItemChangedEndpoint : TeamFoundationServerSensor.EndpointBase {

    /// <summary>
    /// Endpoint required to accept incoming <see href="WorkItemChangedEvent"/> notifications
    /// </summary>
    /// <param name="eventXml">Serialized version of the <see href="WorkItemChangedEvent"/></param>
    /// <param name="tfsIdentityXml">Serialized version of <see href="TFSIdentity"/></param>
    /// <returns>True if method succeeded in reading data. False otherwise.</returns>
    [WebMethod]
    [SoapDocumentMethod("http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify", RequestNamespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
    public override Boolean Notify(string eventXml, string tfsIdentityXml) {
        WorkItemChangedEvent workItemChangedEvent = this.CreateInstance<WorkItemChangedEvent>(eventXml);
        TFSIdentity tfsIdentity = this.CreateInstance<TFSIdentity>(tfsIdentityXml);

        Boolean success = false;

        try {

            // Extra useful data to send.
            Dictionary<string, string> pMap_DevEvent = new Dictionary<string, string>();
            pMap_DevEvent.Add("Project", workItemChangedEvent.PortfolioProject);
            pMap_DevEvent.Add("Title", workItemChangedEvent.Title);
            pMap_DevEvent.Add("WorkItemTitle", workItemChangedEvent.WorkItemTitle);
            pMap_DevEvent.Add("AreaPath", workItemChangedEvent.AreaPath);
            pMap_DevEvent.Add("ChangerSID", workItemChangedEvent.ChangerSid);
            pMap_DevEvent.Add("Type", workItemChangedEvent.ChangeType.ToString());
            pMap_DevEvent.Add("ProjectNodeID", workItemChangedEvent.ProjectNodeId);
            pMap_DevEvent.Add("Subscriber", workItemChangedEvent.Subscriber);
            pMap_DevEvent.Add("TimeZoneOffset", workItemChangedEvent.TimeZoneOffset);
            pMap_DevEvent.Add("URL", workItemChangedEvent.DisplayUrl);


            // Attempt to send any changes to existing items.
            if (workItemChangedEvent.ChangedFields != null) {

                // Integer Fields
                foreach (IntegerField integerField in workItemChangedEvent.ChangedFields.IntegerFields) {
                    pMap_DevEvent.Add("SubType", "Work Item Field Change");
                    pMap_DevEvent.Add("OldValue", integerField.OldValue.ToString());
                    pMap_DevEvent.Add("NewValue", integerField.NewValue.ToString());
                    pMap_DevEvent.Add("ReferenceName", integerField.ReferenceName);
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        integerField.Name, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                    pMap_DevEvent.Remove("OldValue");
                    pMap_DevEvent.Remove("NewValue");
                    pMap_DevEvent.Remove("ReferenceName");
                }

                // String Fields
                foreach (StringField stringField in workItemChangedEvent.ChangedFields.StringFields) {
                    pMap_DevEvent.Add("SubType", "Work Item Field Change");
                    pMap_DevEvent.Add("OldValue", stringField.OldValue);
                    pMap_DevEvent.Add("NewValue", stringField.NewValue);
                    pMap_DevEvent.Add("ReferenceName", stringField.ReferenceName);
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        stringField.Name, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                    pMap_DevEvent.Remove("OldValue");
                    pMap_DevEvent.Remove("NewValue");
                    pMap_DevEvent.Remove("ReferenceName");
                }
            }

            // Attempt to send the work results for files added.
            if (workItemChangedEvent.AddedFiles != null) {
                foreach (string addFile in workItemChangedEvent.AddedFiles) {
                    pMap_DevEvent.Add("SubType", "File Add");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        addFile, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for files deleted.
            if (workItemChangedEvent.DeletedFiles != null) {
                foreach (string deleteFile in workItemChangedEvent.DeletedFiles) {
                    pMap_DevEvent.Add("SubType", "File Delete");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        deleteFile, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for resource links added.
            if (workItemChangedEvent.AddedResourceLinks != null) {
                foreach (string resourceAdd in workItemChangedEvent.AddedResourceLinks) {
                    pMap_DevEvent.Add("SubType", "Link Add");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        resourceAdd, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for resource links deleted.
            if (workItemChangedEvent.DeletedResourceLinks != null) {
                foreach (string resourceDel in workItemChangedEvent.DeletedResourceLinks) {
                    pMap_DevEvent.Add("SubType", "Link Delete");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        resourceDel, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for resource links changed.
            if (workItemChangedEvent.ChangedResourceLinks != null) {
                foreach (string resourceChg in workItemChangedEvent.ChangedResourceLinks) {
                    pMap_DevEvent.Add("SubType", "Link Change");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        resourceChg, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for relations added.
            if (workItemChangedEvent.AddedRelations != null) {
                foreach (string relationAdd in workItemChangedEvent.AddedRelations) {
                    pMap_DevEvent.Add("SubType", "Relation Add");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        relationAdd, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for relations deleted.
            if (workItemChangedEvent.DeletedRelations != null) {
                foreach (string relationDel in workItemChangedEvent.DeletedRelations) {
                    pMap_DevEvent.Add("SubType", "Relation Delete");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        relationDel, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            // Attempt to send the work results for relations changed.
            if (workItemChangedEvent.ChangedRelations != null) {
                foreach (string relationChg in workItemChangedEvent.ChangedRelations) {
                    pMap_DevEvent.Add("SubType", "Relation Change");
                    SensorShellProxy.TheInstance.SendDevEventData("WorkItemChange",
                        relationChg, pMap_DevEvent);
                    pMap_DevEvent.Remove("SubType");
                }
            }

            success = true;
        }
        catch (Exception e) {
            Logger.TheInstance.Log("Error sending WorkEventItem data. Data will be lost. " + e, LogLevel.Error);
        }

        return success;
    }
}